package com.jianguozh.difs.framework.base;

import cn.hutool.core.util.StrUtil;
import com.jianguozh.difs.common.bean.R;
import com.jianguozh.difs.common.constant.ApiErrorCode;
import com.jianguozh.difs.common.exception.DifsException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.validation.ConstraintViolationException;

/**
 * <p>
 * api异常处理器
 * </p>
 *
 * @author hanrs
 * @date 2022/3/23
 */
@Slf4j
@RestControllerAdvice
public class ApiExceptionHandler {

    @ExceptionHandler(DifsException.class)
    public R<ApiErrorCode> handleDifsException(DifsException e) {
        if (e.getErrorCode() != null && StrUtil.isNotBlank(e.getMessage())) {
            return R.failed(e.getErrorCode(), e.getMessage());
        } else if (e.getErrorCode() != null) {
            return R.failed(e.getErrorCode());
        } else {
            return R.failed(e.getMessage());
        }

    }

    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public R<ApiErrorCode> handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
        return R.failed(ApiErrorCode.BAD_CONTENT_TYPE, e.getMessage());
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public R<ApiErrorCode> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e){
        return R.failed(ApiErrorCode.BAD_REQUEST);
    }


    @ExceptionHandler(NoHandlerFoundException.class)
    public R<ApiErrorCode> handleNoFoundException(Exception e) {
        return R.failed(ApiErrorCode.METHOD_NOT_ALLOWED, e.getMessage());
    }


    @ExceptionHandler(IllegalArgumentException.class)
    public R<ApiErrorCode> handleIllegalArgumentException(IllegalArgumentException e) {
        return R.failed(ApiErrorCode.BAD_REQUEST, e.getMessage());

    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public R<ApiErrorCode> handleMissingServletRequestParameterException(
            MissingServletRequestParameterException e) {
        return R.failed(ApiErrorCode.BAD_REQUEST, e.getMessage());
    }

    @ExceptionHandler(AccessDeniedException.class)
    public R<ApiErrorCode> handleAccessDeniedException(AccessDeniedException e){
        return R.failed(ApiErrorCode.ACCESS_DENIED);
    }

    /**
     * 参数反序列化异常(如：枚举类型)
     * @param e
     * @return
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public R<ApiErrorCode> handleHttpMessageNotReadableException(HttpMessageNotReadableException e){
        return R.failed(ApiErrorCode.BAD_REQUEST, e.getMessage());
    }

    /**
     * 接口参数校验异常处理
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R<ApiErrorCode> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        StringBuilder errorMessage = new StringBuilder();
        errorMessage.append("数据校验失败:");
        int i = 1;

        for (ObjectError objectError : bindingResult.getAllErrors()) {
            errorMessage.append(objectError.getDefaultMessage());
            if (i < bindingResult.getFieldErrorCount()) {
                errorMessage.append(", ");
            } else {
                errorMessage.append('.');
            }
        }

        return R.failed(errorMessage.toString());
    }

    @ExceptionHandler(ConstraintViolationException.class)
    public R<ApiErrorCode> handleConstraintViolationException(ConstraintViolationException e){
        return R.failed(ApiErrorCode.BAD_REQUEST, e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public R<ApiErrorCode> handleException(Exception e) {
        log.error("未知异常信息 ex={}", e.getMessage(), e);
        return R.failed(ApiErrorCode.fromCode(ApiErrorCode.INTERNAL_ERROR.getCode()));
    }
}
